#include "framework.h"

struct EncodingProbeContext_UTF8	g_stEncodingProbeContext_UTF8 ;
struct EncodingProbeContext_GB18030	g_stEncodingProbeContext_GB18030 ;
struct EncodingProbeContext_BIG5	g_stEncodingProbeContext_BIG5 ;

void funcInitProbeReader_UTF8( void *ctx )
{
	struct EncodingProbeContext_UTF8	*ctx_UTF8 = (struct EncodingProbeContext_UTF8 *)ctx ;

	ctx_UTF8->flag = 0 ;
	ctx_UTF8->step = 0 ;
	ctx_UTF8->skip = 0 ;

	return;
}

int funcDoProbeReader_UTF8( void *ctx , unsigned char *p_ch , size_t *p_counter )
{
	struct EncodingProbeContext_UTF8	*ctx_UTF8 = (struct EncodingProbeContext_UTF8 *)ctx ;

	if( ctx_UTF8->skip > 0 )
	{
		ctx_UTF8->skip--;
		return -1;
	}

	if( ((*p_ch)>>7) == 0 )
	{
		return 0;
	}
	else if( ((*p_ch)>>5) == 0x06 )
	{
		p_ch++;
		if( (*p_ch) && ((*p_ch)>>6) == 0x02 )
		{
			ctx_UTF8->skip = 1 ;
			(*p_counter)++;
			return 1;
		}
	}
	else if( ((*p_ch)>>4) == 0x0E )
	{
		p_ch++;
		if( (*p_ch) && ((*p_ch)>>6) == 0x02 )
		{
			p_ch++;
			if( (*p_ch) && ((*p_ch)>>6) == 0x02 )
			{
				ctx_UTF8->skip = 2 ;
				(*p_counter)++;
				return 1;
			}
		}
	}
	else if( ((*p_ch)>>3) == 0x1E )
	{
		p_ch++;
		if( (*p_ch) && ((*p_ch)>>6) == 0x02 )
		{
			p_ch++;
			if( (*p_ch) && ((*p_ch)>>6) == 0x02 )
			{
				p_ch++;
				if( (*p_ch) && ((*p_ch)>>6) == 0x02 )
				{
					ctx_UTF8->skip = 3 ;
					(*p_counter)++;
					return 1;
				}
			}
		}
	}
	else if( ((*p_ch)>>2) == 0x3E )
	{
		p_ch++;
		if( (*p_ch) && ((*p_ch)>>6) == 0x02 )
		{
			p_ch++;
			if( (*p_ch) && ((*p_ch)>>6) == 0x02 )
			{
				p_ch++;
				if( (*p_ch) && ((*p_ch)>>6) == 0x02 )
				{
					p_ch++;
					if( (*p_ch) && ((*p_ch)>>6) == 0x02 )
					{
						ctx_UTF8->skip = 4 ;
						(*p_counter)++;
						return 1;
					}
				}
			}
		}
	}
	else if( ((*p_ch)>>1) == 0x7E )
	{
		p_ch++;
		if( (*p_ch) && ((*p_ch)>>6) == 0x02 )
		{
			p_ch++;
			if( (*p_ch) && ((*p_ch)>>6) == 0x02 )
			{
				p_ch++;
				if( (*p_ch) && ((*p_ch)>>6) == 0x02 )
				{
					p_ch++;
					if( (*p_ch) && ((*p_ch)>>6) == 0x02 )
					{
						p_ch++;
						if( (*p_ch) && ((*p_ch)>>6) == 0x02 )
						{
							ctx_UTF8->skip = 5 ;
							(*p_counter)++;
							return 1;
						}
					}
				}
			}
		}
	}

	return 0;
}

void funcInitProbeReader_GB18030( void *ctx )
{
	struct EncodingProbeContext_GB18030	*ctx_GB18030 = (struct EncodingProbeContext_GB18030 *)ctx ;

	ctx_GB18030->skip = 0 ;

	return;
}

int funcDoProbeReader_GB18030( void *ctx , unsigned char *p_ch , size_t *p_counter )
{
	struct EncodingProbeContext_GB18030	*ctx_GB18030 = (struct EncodingProbeContext_GB18030 *)ctx ;

	if( ctx_GB18030->skip > 0 )
	{
		ctx_GB18030->skip--;
		return -1;
	}

	if( 0xB0 <= (*p_ch) && (*p_ch) <= 0xF7 )
	{
		p_ch++;
		if( (*p_ch) && 0xA1 <= (*p_ch) && (*p_ch) <= 0xFE )
		{
			ctx_GB18030->skip = 1 ;
			(*p_counter)++;
			return 1;
		}
	}
	else if( 0x81 <= (*p_ch) && (*p_ch) <= 0xA0 )
	{
		p_ch++;
		if( (*p_ch) && 0x40 <= (*p_ch) && (*p_ch) <= 0xFE )
		{
			ctx_GB18030->skip = 1 ;
			(*p_counter)++;
			return 1;
		}
	}
	else if( 0xAA <= (*p_ch) && (*p_ch) <= 0xFE )
	{
		p_ch++;
		if( (*p_ch) && 0x40 <= (*p_ch) && (*p_ch) <= 0xA0 )
		{
			ctx_GB18030->skip = 1 ;
			(*p_counter)++;
			return 1;
		}
	}
	else if( 0x81 <= (*p_ch) && (*p_ch) <= 0x82 )
	{
		p_ch++;
		if( (*p_ch) && 0x30 <= (*p_ch) && (*p_ch) <= 0x39 )
		{
			p_ch++;
			if( (*p_ch) && 0x81 <= (*p_ch) && (*p_ch) <= 0xFE )
			{
				p_ch++;
				if( (*p_ch) && 0x30 <= (*p_ch) && (*p_ch) <= 0x39 )
				{
					ctx_GB18030->skip = 3 ;
					(*p_counter)++;
					return 1;
				}
			}
		}
	}
	else if( 0x95 <= (*p_ch) && (*p_ch) <= 0x98 )
	{
		p_ch++;
		if( (*p_ch) && 0x30 <= (*p_ch) && (*p_ch) <= 0x39 )
		{
			p_ch++;
			if( (*p_ch) && 0x81 <= (*p_ch) && (*p_ch) <= 0xFE )
			{
				p_ch++;
				if( (*p_ch) && 0x30 <= (*p_ch) && (*p_ch) <= 0x39 )
				{
					ctx_GB18030->skip = 3 ;
					(*p_counter)++;
					return 1;
				}
			}
		}
	}

	return 0;
}

void funcInitProbeReader_BIG5( void *ctx )
{
	struct EncodingProbeContext_BIG5	*ctx_BIG5 = (struct EncodingProbeContext_BIG5 *)ctx ;

	ctx_BIG5->flag = 0 ;
	ctx_BIG5->skip = 0 ;

	return;
}

int funcDoProbeReader_BIG5( void *ctx , unsigned char *p_ch , size_t *p_counter )
{
	struct EncodingProbeContext_BIG5	*ctx_BIG5 = (struct EncodingProbeContext_BIG5 *)ctx ;

	if( ctx_BIG5->skip > 0 )
	{
		ctx_BIG5->skip--;
		return -1;
	}

	if( 0x81 <= (*p_ch) && (*p_ch) <= 0xFE )
	{
		p_ch++;
		if( (*p_ch) && ( 0x40 <= (*p_ch) && (*p_ch) <= 0x7E ) || ( 0xA1 <= (*p_ch) && (*p_ch) <= 0xFE ) )
		{
			ctx_BIG5->skip = 1 ;
			(*p_counter)++;
			return 1;
		}
	}

	return 0;
}

struct EncodingProbe	g_astEncodingProbe[] =
{
	{ ENCODING_UTF8 , ENCODING_UTF8_STR , & funcInitProbeReader_UTF8 , & funcDoProbeReader_UTF8 , & g_stEncodingProbeContext_UTF8 } ,
	{ ENCODING_GBK , ENCODING_GBK_STR , & funcInitProbeReader_GB18030 , & funcDoProbeReader_GB18030 , & g_stEncodingProbeContext_GB18030 } ,
	{ ENCODING_BIG5 , ENCODING_BIG5_STR , & funcInitProbeReader_BIG5 , & funcDoProbeReader_BIG5 , & g_stEncodingProbeContext_BIG5 } ,
	{ 0 , NULL , 0 , NULL }
};

void InitEncodingProbe( struct EncodingProbe *ep )
{
	struct EncodingProbe	*p_ep = NULL ;

	for( p_ep = g_astEncodingProbe ; p_ep->pfuncDoProbeReader ; p_ep++ )
	{
		p_ep->pfuncInitProbeReader( p_ep->pContext );
		p_ep->nProbeCounter = 0 ;
	}

	return;
}

void DoEncodingProbe( struct EncodingProbe *ep , char *str , size_t len )
{
	unsigned char		*p = NULL ;
	size_t			l ;
	struct EncodingProbe	*p_ep = NULL ;
	int			nret = 0 ;

	for( l = 0 , p = (unsigned char *)str ; l < len ; l++ , p++ )
	{
		for( p_ep = g_astEncodingProbe ; p_ep->pfuncDoProbeReader ; p_ep++ )
		{
			nret = p_ep->pfuncDoProbeReader( p_ep->pContext , p , & (p_ep->nProbeCounter) ) ;
			if( nret == 1 )
				break;
		}
	}

	return;
}

UINT GetCodePageFromEncodingProbe( struct EncodingProbe *ep )
{
	struct EncodingProbe	*p_ep = NULL ;
	struct EncodingProbe	*max = NULL ;

	for( max = g_astEncodingProbe , p_ep = g_astEncodingProbe+1 ; p_ep->pfuncDoProbeReader ; p_ep++ )
	{
		if( p_ep->nProbeCounter > max->nProbeCounter )
			max = p_ep ;
	}

	if( max->nProbeCounter == 0 )
	{
		return GetACP();
	}
	else
	{
		return max->nCodePage;
	}
}

const char *GetEncodingString( UINT nCodePage )
{
	struct EncodingProbe	*p_ep = NULL ;

	for( p_ep = g_astEncodingProbe ; p_ep->pfuncDoProbeReader ; p_ep++ )
	{
		if( p_ep->nCodePage == nCodePage )
			return p_ep->acCodePage;
	}

	return NULL;
}

void InitNewLineModeProbe( struct NewLineProbe *elp )
{
	memset( elp , 0x00 , sizeof(struct NewLineProbe) );
	elp->nNewLineMode = -1 ;

	return;
}

void DoNewLineModeProbe( struct NewLineProbe *elp , char *str , size_t len )
{
	if( elp->nNewLineMode == -1 )
	{
		char *p = (char*)memchr( (void*)str , '\n' , len ) ;
		if( p )
		{
			if( p > str )
			{
				if( *(p-1) == '\r' )
					elp->nNewLineMode = 0 ;
				else
					elp->nNewLineMode = 2 ;
			}
		}
		else
		{
			char *p = (char*)memchr( (void*)str , '\r' , len ) ;
			if( p )
				elp->nNewLineMode = 1 ;
		}
	}

	return;
}

int GetNewLineModeFromProbe( struct NewLineProbe *elp , int nNewLineModeDefault )
{
	if( elp->nNewLineMode == -1 )
		return nNewLineModeDefault;
	else
		return elp->nNewLineMode;
}
